package com.emser.unc.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jdo.JDOCanRetryException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.datanucleus.store.appengine.query.JDOCursorHelper;

import com.emser.unc.serializable.DataStoreVersion;
import com.emser.unc.serializable.ResultDTO;
import com.emser.unc.serializable.SellerDTO;
import com.emser.unc.server.domain.Seller;
import com.emser.unc.server.domain.SellerCustomers;
import com.emser.unc.server.domain.SellerProducts;
import com.emser.unc.server.domain.UserAccount;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class AppLibSeller {
	private static final int NUM_RETRIES = 5;
	public static Seller getSellerAuthenticated(SellerDTO sellerData) {
		String userNameParam = sellerData.getUserName() ,passwordParam = sellerData.getUserPassword();
		Seller oneResult = null, detached = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Query q = pm.newQuery(Seller.class, "userName == :userNameParam && password == :passwordParam");
		q.setUnique(true);
	    try {
	        oneResult = (Seller) q.execute(userNameParam, passwordParam);
			if (oneResult != null) {
				if(oneResult.getSerialDevice()== null||oneResult.getSerialDevice().equals("")){
					oneResult.setSerialDevice(sellerData.getSerialDevice());
					AppLibDevices.newDevice(oneResult, oneResult.getKey().getParent().getName());
					detached = pm.detachCopy(oneResult);
				}else{
					if(oneResult.getSerialDevice().equals(sellerData.getSerialDevice()))
						detached = pm.detachCopy(oneResult);
				}
			}
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      detached = null;
	    }
	    finally {
	      q.closeAll();
	      pm.close();
	    }
		return detached;	
	}
	
	public static SellerDTO getSellerDataStore(SellerDTO seller){
		Seller sellerDB = getSellerAuthenticated(seller);
		if(sellerDB != null)
			return Seller.toDTO(sellerDB);	
		else return null;
	}
	
	public static Seller getSeller(String userNameSellerParam) {
		Seller oneResult = null, detached = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Query q = pm.newQuery(Seller.class, "userName == :userNameSellerParam");
		q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        oneResult = (Seller) q.execute(userNameSellerParam);
			if (oneResult != null) {
				detached = pm.detachCopy(oneResult);
			}
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      q.closeAll();
	      pm.close();
	    }
		return detached;	
	}
	
	public static DataStoreVersion getVersionSeller(SellerDTO sellerDTO){
		Seller seller = getSeller(sellerDTO.getUserName());
		DataStoreVersion result = new DataStoreVersion();
		result.setCustomersVersion(seller.getVersionCustomer());
		result.setProductsVersion(seller.getVersionProduct());
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static ResultDTO<SellerDTO> searchSellers(String cursorString, int range,ArrayList<String> searchParam) {
		List<Seller> sellersDB = null;
		List<Seller> sellersDBCopy = null;
		ResultDTO<SellerDTO> result = null;
		Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), searchParam.get(0));
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Seller.class);
		if (searchParam.size() == 2){	
			q.setFilter("firstName >= :1 && firstName < :2 && userA == :3");
			q.setOrdering("firstName asc");
			q.setRange(0, range);
			if (cursorString != null) {
	        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
	        	Map<String, Object> extensionMap = new HashMap<String, Object>();
	        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
	        	q.setExtensions(extensionMap);
	        }
			sellersDB = (List<Seller>) q.execute(searchParam.get(1)  , (searchParam.get(1) + "\ufffd"),userName);	
		}
		if (searchParam.size() == 3){
			q.declareParameters("String first, String lastN, String lastN1,com.google.appengine.api.datastore.Key uName");
			q.setFilter("firstName == first && lastName >= lastN && lastName < lastN1 && userA == uName");
			q.setOrdering("firstName asc");
			q.setRange(0, range);
			if (cursorString != null) {
	        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
	        	Map<String, Object> extensionMap = new HashMap<String, Object>();
	        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
	        	q.setExtensions(extensionMap);
	        }
			Object[] parameters = new Object[]{ searchParam.get(1), searchParam.get(2), searchParam.get(2)+"\ufffd", userName };
			sellersDB = (List<Seller>) q.executeWithArray(parameters);
		}
		if (searchParam.size() == 4){
			q.declareParameters("String first, String lastN, String uN, String uN1,com.google.appengine.api.datastore.Key uName");
			q.setFilter("firstName == first && lastName == lastN&& userName >= uN && userName < uN1 && userA == uName");
			q.setOrdering("firstName asc");
			q.setRange(0, range);
			if (cursorString != null) {
	        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
	        	Map<String, Object> extensionMap = new HashMap<String, Object>();
	        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
	        	q.setExtensions(extensionMap);
	        }
			Object[] parameters = new Object[] { searchParam.get(1), searchParam.get(2), searchParam.get(3) ,searchParam.get(3)+"\ufffd", userName };
			sellersDB = (List<Seller>) q.executeWithArray(parameters);	
		}
		if (sellersDB != null) {
			sellersDBCopy = (List<Seller>)pm.detachCopyAll(sellersDB);
	        Cursor cursor = JDOCursorHelper.getCursor(sellersDB);
	        cursorString = cursor.toWebSafeString();
	        result = new ResultDTO<SellerDTO>();
	        result.setCursorString(cursorString);
			result.setList(toDTO(sellersDBCopy));
        }
		q.closeAll();
		pm.close();
		return result;	
	}	
	
	public static ArrayList<SellerDTO> toDTO(List<Seller> sellers){
		ArrayList<SellerDTO> sellersDTO = new ArrayList<SellerDTO>();
        for(int i = 0;i<sellers.size();i++)
        	sellersDTO.add(Seller.toDTO(sellers.get(i)));
        return sellersDTO;
	}
	
	@SuppressWarnings("unchecked")
	public static Integer getSearchResultsCount(ArrayList<String> searchParam) {
		List<Seller> sellersDB = new ArrayList<Seller>();
		Integer resulta = 0;
		Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), searchParam.get(0));
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Seller.class);
		if (searchParam.size() == 2){		
			q.setFilter("firstName >= :1 && firstName < :2 && userA == :3");
			sellersDB = (List<Seller>) q.execute(searchParam.get(1)  , (searchParam.get(1) + "\ufffd"),userName);
		}
		if (searchParam.size() == 3){
			q.declareParameters("String first, String lastN, String lastN1,com.google.appengine.api.datastore.Key uName");
			q.setFilter("firstName == first && lastName >= lastN && lastName < lastN1 && userA == uName");
	        Object[] parameters = new Object[]{ searchParam.get(1), searchParam.get(2), searchParam.get(2)+"\ufffd", userName };
			sellersDB = (List<Seller>) q.executeWithArray(parameters);
		}
		if (searchParam.size() == 4){
			q.declareParameters("String first, String lastN, String uN, String uN1,com.google.appengine.api.datastore.Key uName");
			q.setFilter("firstName == first && lastName == lastN&& userName >= uN && userName < uN1 && userA == uName");
			Object[] parameters = new Object[] { searchParam.get(1), searchParam.get(2), searchParam.get(3) ,searchParam.get(3)+"\ufffd", userName };
			sellersDB = (List<Seller>) q.executeWithArray(parameters);			
		}
		if(sellersDB != null)
			resulta = sellersDB.size();
		q.closeAll();
		pm.close();
		return resulta;	
	}	
	
	public static SellerDTO getSellerDTO(String userNameSeller){
		Seller sellerDB = getSeller(userNameSeller);
		if (sellerDB != null)
			return Seller.toDTO(sellerDB);
		else return null;
	}
	
	@SuppressWarnings("unchecked")
	public static ResultDTO<SellerDTO> getSellersDataStore(String cursorString, int range,String userAccountName){
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    List<Seller> sellersDB = null;
		List<Seller> sellersDBCopy = null;
		ResultDTO<SellerDTO> result = null;
	    Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(Seller.class);
	    q.setFilter("userA == :userName");
	    q.setOrdering("firstName asc");
	    q.setRange(0, range);
	    if (cursorString != null) {
        	Cursor cursor = Cursor.fromWebSafeString(cursorString);
        	Map<String, Object> extensionMap = new HashMap<String,Object>();
        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
        	q.setExtensions(extensionMap);
        }
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        sellersDB =(List<Seller>) q.execute(userName); 
	        if ((sellersDB != null) && (!sellersDB.isEmpty())) {
				sellersDBCopy = (List<Seller>)pm.detachCopyAll(sellersDB);
		        Cursor cursor = JDOCursorHelper.getCursor(sellersDB);
		        cursorString = cursor.toWebSafeString();
		        result = new ResultDTO<SellerDTO>();
		        result.setCursorString(cursorString);
				result.setList(toDTO(sellersDBCopy));
	        }
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      result = null;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }	
	    return result;
	}
	
	
	@SuppressWarnings("unchecked")
	public static Integer getSellersCount(String userAccountName){
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Integer sellerCount = 0;
	    List<Seller> sellerList = null;
		List<Seller> resulta = null;
	    Key userName = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    Query q = pm.newQuery(Seller.class);
	    q.setFilter("userA == :userName");
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        sellerList =(List<Seller>) q.execute(userName); 
	        resulta = (List<Seller>)pm.detachCopyAll(sellerList);
	        if((resulta != null) && (!resulta.isEmpty()))
	        	sellerCount = resulta.size();
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
		return sellerCount;
	}
	
	public static synchronized boolean updateSellerDataStore(SellerDTO seller) {
		boolean result = false;
		Seller oneResult = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Query q = pm.newQuery(Seller.class, "userName == :userNameParam");
		q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        oneResult = (Seller) q.execute(seller.getUserName());
	        if(oneResult != null){
	        	oneResult.setPassword(seller.getUserPassword());
	        	oneResult.setLastName(seller.getLastName());
	        	oneResult.setFirstName(seller.getFirstName());
	        	oneResult.setAddress(seller.getAddress());
	        	oneResult.setTelephone(seller.getTelephone());
	        	oneResult.setCity(seller.getCity());
	        	oneResult.setZipCode(seller.getZipCode());
	        	result = true;
	        }
	        try {
	          tx.commit();	          
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      return false;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      q.closeAll();
	      pm.close();
	    }
		return result;
	}
	
	public static synchronized boolean deleteSellerDataStore(String userAccountName,String sellerName) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    SellerProducts sellerProducts = null;
	    boolean result = false;
	    SellerCustomers sellerCustomers = null;
	    KeyFactory.Builder keyBuilderOne = new KeyFactory.Builder(UserAccount.class.getSimpleName(), userAccountName);
    	keyBuilderOne.addChild(Seller.class.getSimpleName(), sellerName).addChild(SellerProducts.class.getSimpleName(), sellerName);
    	Key ckeyOne = keyBuilderOne.getKey(); 
    	KeyFactory.Builder keyBuilderTwo = new KeyFactory.Builder(UserAccount.class.getSimpleName(), userAccountName);
    	keyBuilderTwo.addChild(Seller.class.getSimpleName(), sellerName).addChild(SellerCustomers.class.getSimpleName(), sellerName);
    	Key ckeyTwo = keyBuilderTwo.getKey(); 
	    Query q = pm.newQuery(Seller.class, "userName == :userNameParam");
		q.setUnique(true);
	    try {			
			Seller toRemove = (Seller) q.execute(sellerName);
			if(toRemove != null){
				try{
					sellerProducts = pm.getObjectById(SellerProducts.class, ckeyOne);
					AppLibProduct.deletePSellerReferences(userAccountName, sellerName, sellerProducts.getCodeProducts());
					pm.deletePersistent(sellerProducts);
				}catch(javax.jdo.JDOObjectNotFoundException e){}
				try{
					sellerCustomers = pm.getObjectById(SellerCustomers.class,ckeyTwo);
					AppLibCustomer.deleteCSellerReferences(userAccountName,sellerName,sellerCustomers.getIdCustomers());
					pm.deletePersistent(sellerCustomers);
				}catch(javax.jdo.JDOObjectNotFoundException e){}			
				pm.deletePersistent(toRemove);
				result = true;
			}
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      result = false;
	    }
	    finally {     
	      pm.close();
	      q.closeAll();
	    }
		return result;
	}
	
	public static boolean addSellerDataStore(String userAccountName, SellerDTO sellerDTO) {
		Seller defaultSeller = AppLibSeller.getSeller(sellerDTO.getUserName());
		if (defaultSeller != null)
			return false;  
		Seller seller = createSellerDB(sellerDTO);
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    UserAccount user = null;
	    Key k = KeyFactory.createKey(UserAccount.class.getSimpleName(), userAccountName);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        user = pm.getObjectById(UserAccount.class, k);
	        user.addSeller(seller);
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      return false;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	    }
		return true;
	}
	
	public static List<Long> getSellerCustomersId(String userNameSeller){
		List<Long> result;
		SellerCustomers sellerCustomers = AppLibCustomer.getSellerCustomers(userNameSeller);
		if(sellerCustomers == null)
			result = new ArrayList<Long>();
		else
			result = sellerCustomers.getIdCustomers();
		return result;
	}
	
	private static Seller createSellerDB(SellerDTO sellerDTO){
		Seller seller = new Seller();
		seller.setFirstName(sellerDTO.getFirstName());
		seller.setLastName(sellerDTO.getLastName());
		seller.setAddress(sellerDTO.getAddress());
		seller.setCity(sellerDTO.getCity());
		seller.setZipCode(sellerDTO.getZipCode());
		seller.setTelephone(sellerDTO.getTelephone());
		seller.setUserName(sellerDTO.getUserName());
		seller.setPassword(sellerDTO.getUserPassword());
		seller.setVersionCustomer(new Long(0));
		seller.setVersionProduct(new Long(0));
		return seller;
	}
		
	
}
